#!/usr/bin/env python3
"""
智能延迟管理器 - P2级性能优化
实现动态延迟调整、错误恢复、分层延迟策略
TODO-006: 实现智能延迟策略 ✅
"""

import time
import random
from datetime import datetime, timedelta
import logging

logger = logging.getLogger(__name__)

class SmartDelayManager:
    """智能延迟管理器 - 动态调整延迟策略"""
    
    def __init__(self):
        # 基础延迟配置（秒）
        self.base_delays = {
            'city_switch': 67.5,      # 城市切换：60-75秒
            'category_switch': 30,    # 品类切换：25-35秒（优化）
            'page_turn': 20,          # 页面翻页：15-25秒（优化）
            'normal': 15,             # 常规操作：10-20秒
            'error_recovery': 30      # 错误恢复：基础30秒
        }
        
        # 随机延迟范围（秒）
        self.random_ranges = {
            'city_switch': 7.5,       # ±7.5秒
            'category_switch': 5,     # ±5秒
            'page_turn': 5,           # ±5秒
            'normal': 5,              # ±5秒
            'error_recovery': 15      # ±15秒
        }
        
        # 动态调整参数
        self.performance_history = []
        self.error_count = 0
        self.success_count = 0
        self.last_error_time = None
        
        # 延迟调整系数
        self.adjustment_factors = {
            'error_penalty': 1.5,     # 出错时延迟增加50%
            'success_bonus': 0.95,    # 成功时延迟减少5%
            'max_adjustment': 2.0,    # 最大调整倍数
            'min_adjustment': 0.7     # 最小调整倍数
        }
        
        logger.info("[DELAY] 智能延迟管理器初始化完成")
        
    def get_smart_delay(self, delay_type, response_time=None, is_error=False):
        """获取智能调整后的延迟时间"""
        
        # 获取基础延迟
        base_delay = self.base_delays.get(delay_type, self.base_delays['normal'])
        random_range = self.random_ranges.get(delay_type, self.random_ranges['normal'])
        
        # 计算动态调整系数
        adjustment_factor = self._calculate_adjustment_factor(delay_type, response_time, is_error)
        
        # 应用调整系数
        adjusted_base = base_delay * adjustment_factor
        
        # 添加随机延迟
        final_delay = adjusted_base + random.uniform(-random_range, random_range)
        
        # 确保延迟在合理范围内
        min_delay = base_delay * self.adjustment_factors['min_adjustment']
        max_delay = base_delay * self.adjustment_factors['max_adjustment']
        final_delay = max(min_delay, min(max_delay, final_delay))
        
        # 记录性能数据
        self._record_performance(delay_type, final_delay, response_time, is_error)
        
        return final_delay
        
    def _calculate_adjustment_factor(self, delay_type, response_time, is_error):
        """计算动态调整系数"""
        factor = 1.0
        
        # 错误调整
        if is_error:
            self.error_count += 1
            self.last_error_time = datetime.now()
            factor *= self.adjustment_factors['error_penalty']
            logger.warning(f"[DELAY] 检测到错误，延迟增加 {(factor-1)*100:.1f}%")
        else:
            self.success_count += 1
            
            # 连续成功时逐步减少延迟
            if self.success_count > 3 and self.error_count == 0:
                factor *= self.adjustment_factors['success_bonus']
                logger.info(f"[DELAY] 连续成功，延迟优化 {(1-factor)*100:.1f}%")
        
        # 基于响应时间调整
        if response_time:
            if response_time > 10:  # 响应时间超过10秒
                factor *= 1.2
                logger.info(f"[DELAY] 响应时间较慢({response_time:.1f}s)，延迟增加20%")
            elif response_time < 3:  # 响应时间小于3秒
                factor *= 0.9
                logger.info(f"[DELAY] 响应时间较快({response_time:.1f}s)，延迟减少10%")
        
        # 近期错误影响
        if self.last_error_time:
            time_since_error = (datetime.now() - self.last_error_time).total_seconds()
            if time_since_error < 300:  # 5分钟内有错误
                error_factor = 1.0 + (300 - time_since_error) / 600  # 逐步恢复
                factor *= error_factor
        
        # 限制调整范围
        factor = max(self.adjustment_factors['min_adjustment'], 
                    min(self.adjustment_factors['max_adjustment'], factor))
        
        return factor
        
    def _record_performance(self, delay_type, delay_used, response_time, is_error):
        """记录性能数据"""
        record = {
            'timestamp': datetime.now(),
            'delay_type': delay_type,
            'delay_used': delay_used,
            'response_time': response_time,
            'is_error': is_error
        }
        
        self.performance_history.append(record)
        
        # 保持历史记录在合理范围内
        if len(self.performance_history) > 100:
            self.performance_history = self.performance_history[-50:]
            
    def execute_smart_delay(self, delay_type, response_time=None, is_error=False):
        """执行智能延迟"""
        delay_time = self.get_smart_delay(delay_type, response_time, is_error)
        
        # 延迟类型说明
        delay_descriptions = {
            'city_switch': '城市切换',
            'category_switch': '品类切换',
            'page_turn': '页面翻页',
            'normal': '常规操作',
            'error_recovery': '错误恢复'
        }
        
        description = delay_descriptions.get(delay_type, delay_type)
        logger.info(f"[DELAY] {description}延迟: {delay_time:.1f}秒")
        
        # 执行延迟
        time.sleep(delay_time)
        
        return delay_time
        
    def get_error_recovery_delay(self, error_count=1):
        """获取错误恢复延迟"""
        base_delay = self.base_delays['error_recovery']
        
        # 根据错误次数增加延迟
        multiplier = min(error_count * 0.5 + 1, 3.0)  # 最多3倍延迟
        recovery_delay = base_delay * multiplier
        
        # 添加随机延迟
        random_range = self.random_ranges['error_recovery']
        final_delay = recovery_delay + random.uniform(-random_range, random_range)
        
        logger.warning(f"[DELAY] 错误恢复延迟(第{error_count}次): {final_delay:.1f}秒")
        
        time.sleep(final_delay)
        return final_delay
        
    def reset_error_state(self):
        """重置错误状态"""
        self.error_count = 0
        self.last_error_time = None
        logger.info("[DELAY] 错误状态已重置")
        
    def get_performance_stats(self):
        """获取性能统计"""
        if not self.performance_history:
            return None
            
        total_records = len(self.performance_history)
        error_records = sum(1 for r in self.performance_history if r['is_error'])
        
        # 计算平均延迟
        avg_delays = {}
        for delay_type in self.base_delays.keys():
            type_records = [r for r in self.performance_history if r['delay_type'] == delay_type]
            if type_records:
                avg_delays[delay_type] = sum(r['delay_used'] for r in type_records) / len(type_records)
        
        # 计算平均响应时间
        response_times = [r['response_time'] for r in self.performance_history if r['response_time']]
        avg_response_time = sum(response_times) / len(response_times) if response_times else None
        
        stats = {
            'total_operations': total_records,
            'error_rate': error_records / total_records if total_records > 0 else 0,
            'success_count': self.success_count,
            'error_count': self.error_count,
            'avg_delays': avg_delays,
            'avg_response_time': avg_response_time,
            'last_error_time': self.last_error_time
        }
        
        return stats
        
    def print_performance_report(self):
        """打印性能报告"""
        stats = self.get_performance_stats()
        
        if not stats:
            logger.info("[DELAY] 暂无性能数据")
            return
            
        logger.info("[DELAY] ===== 智能延迟性能报告 =====")
        logger.info(f"[DELAY] 总操作次数: {stats['total_operations']}")
        logger.info(f"[DELAY] 成功次数: {stats['success_count']}")
        logger.info(f"[DELAY] 错误次数: {stats['error_count']}")
        logger.info(f"[DELAY] 错误率: {stats['error_rate']:.1%}")
        
        if stats['avg_response_time']:
            logger.info(f"[DELAY] 平均响应时间: {stats['avg_response_time']:.1f}秒")
            
        logger.info("[DELAY] 平均延迟时间:")
        for delay_type, avg_delay in stats['avg_delays'].items():
            base_delay = self.base_delays[delay_type]
            optimization = (base_delay - avg_delay) / base_delay * 100
            logger.info(f"[DELAY]   {delay_type}: {avg_delay:.1f}秒 (优化: {optimization:+.1f}%)")
            
        if stats['last_error_time']:
            time_since_error = (datetime.now() - stats['last_error_time']).total_seconds()
            logger.info(f"[DELAY] 距离上次错误: {time_since_error:.0f}秒")
            
        logger.info("[DELAY] ================================")

class DelayOptimizer:
    """延迟优化器 - 提供便捷的延迟优化方法"""
    
    def __init__(self, smart_delay_manager):
        self.delay_manager = smart_delay_manager
        
    def optimize_crawl_delays(self, total_categories, total_pages):
        """优化爬取延迟策略"""
        
        # 计算预期时间节省
        original_time = self._calculate_original_time(total_categories, total_pages)
        optimized_time = self._calculate_optimized_time(total_categories, total_pages)
        
        time_saved = original_time - optimized_time
        optimization_rate = time_saved / original_time * 100
        
        logger.info(f"[OPTIMIZER] 延迟优化预期效果:")
        logger.info(f"[OPTIMIZER]   原始预期时间: {original_time/60:.1f}分钟")
        logger.info(f"[OPTIMIZER]   优化后时间: {optimized_time/60:.1f}分钟")
        logger.info(f"[OPTIMIZER]   节省时间: {time_saved/60:.1f}分钟")
        logger.info(f"[OPTIMIZER]   优化率: {optimization_rate:.1f}%")
        
        return {
            'original_time': original_time,
            'optimized_time': optimized_time,
            'time_saved': time_saved,
            'optimization_rate': optimization_rate
        }
        
    def _calculate_original_time(self, total_categories, total_pages):
        """计算原始延迟时间"""
        # P1版本的延迟配置
        original_delays = {
            'category_switch': 40,  # 品类切换40秒
            'page_turn': 30,        # 翻页30秒
            'normal': 30            # 常规30秒
        }
        
        category_time = total_categories * original_delays['category_switch']
        page_time = total_pages * original_delays['page_turn']
        
        return category_time + page_time
        
    def _calculate_optimized_time(self, total_categories, total_pages):
        """计算优化后延迟时间"""
        # P2版本的优化延迟配置
        optimized_delays = {
            'category_switch': 30,  # 品类切换30秒（优化25%）
            'page_turn': 20,        # 翻页20秒（优化33%）
        }
        
        category_time = total_categories * optimized_delays['category_switch']
        page_time = total_pages * optimized_delays['page_turn']
        
        return category_time + page_time

def test_smart_delay_manager():
    """测试智能延迟管理器"""
    print("🧪 测试智能延迟管理器")
    
    # 创建延迟管理器
    delay_manager = SmartDelayManager()
    
    # 测试不同类型的延迟
    test_scenarios = [
        ('normal', None, False),
        ('page_turn', 5.0, False),
        ('category_switch', 8.0, False),
        ('page_turn', 15.0, True),  # 模拟错误
        ('error_recovery', None, False),
        ('page_turn', 3.0, False),  # 快速响应
    ]
    
    print("\n测试延迟调整:")
    for delay_type, response_time, is_error in test_scenarios:
        delay_time = delay_manager.get_smart_delay(delay_type, response_time, is_error)
        status = "❌ 错误" if is_error else "✅ 成功"
        response_info = f", 响应时间: {response_time}s" if response_time else ""
        print(f"  {delay_type}: {delay_time:.1f}s ({status}{response_info})")
    
    # 打印性能报告
    print("\n性能报告:")
    delay_manager.print_performance_report()
    
    # 测试延迟优化器
    print("\n测试延迟优化器:")
    optimizer = DelayOptimizer(delay_manager)
    optimization_result = optimizer.optimize_crawl_delays(total_categories=6, total_pages=12)
    
    return delay_manager

if __name__ == "__main__":
    # 配置日志
    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
    
    test_smart_delay_manager()
